package org.example;

import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 一致性 hash 算法
 * @author shenguangyang
 */
public class LbConsistentHash extends LoadBalance {
    private static final TreeMap<Integer, String> virtualNodes = new TreeMap<>();
    private static final int VIRTUAL_NODES = 160;
    private static final AtomicInteger clientIp = new AtomicInteger(0);

    public static void main(String[] args) {
        LoadBalance loadBalance = new LbConsistentHash();
        loadBalance.printf();
    }

    static {
        for (int i = 0; i < ServerIps.LIST.size(); i++) {
            for (int j = 0; j < VIRTUAL_NODES; j++) {
                int hash = getHash(ServerIps.LIST.get(i) + i);
                virtualNodes.put(hash, ServerIps.LIST.get(i));
            }
        }
    }

    private static int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash ^ str.charAt(i)) * p;
        }
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;

        if (hash < 0) {
            hash = Math.abs(hash);
        }
        return hash;
    }
    @Override
    public String getServer() {
        int hash = getHash(clientIp.addAndGet(1) + "");
        // 大于hash, virtualNodes的子树的firstKey
        SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash);
        Integer firstKey = null;
        if (subMap.isEmpty()) {
            firstKey = virtualNodes.firstKey();
        } else {
            firstKey = subMap.firstKey();
        }
        return virtualNodes.get(firstKey);
    }
}
